package com.hzb.LNReader.reader;

import java.io.File;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.hzb.LNReader.ImageViewerActivity;
import com.hzb.LNReader.R;
import com.hzb.LNReader.ReaderRecord;
import com.hzb.LNReader.util.ReaderPref;

public class ReaderView extends ScrollView {
	private final String headReachStr;
	private final String tailReachStr;
	private final String loadingStr;
	private final int screenHeight;
	private final int screenWidth;
	
	private final int fontColor;
	private final int fontSize;
	private final int viewHeightLimit;
	
	private TextView headText;
	private TextView tailText;
	
	private final LinearLayout contentList;
	
	private final ReaderRecord currFile;
	private final String fileParent;
	
	private LinearLayout appendarList;
	private int pendingHeight;
	private int startOffset;
	
	private int seqFrom;
	private int seqTo;
	private int lineHeight;
	private boolean justReset;
	
	private boolean showImage = true;
	
	public ReaderView(Context context, ReaderRecord currFile) {
		super(context);
		if (ReaderPref.isScreenNotTimeout()) {
			this.setKeepScreenOn(true);
		}
		this.fontColor = ReaderPref.getFontColor();
		this.fontSize = ReaderPref.getFontSize();
		this.viewHeightLimit = ReaderPref.getViewHeight();
		
		Activity activity = (Activity) context;

		this.headReachStr = context.getString(R.string.headReach);
		this.tailReachStr = context.getString(R.string.bottomReach);
		this.loadingStr = context.getString(R.string.loading);
		
		WindowManager wm = activity.getWindowManager();
		Display dis = wm.getDefaultDisplay();
		this.screenHeight = dis.getHeight();
		this.screenWidth = dis.getWidth();
		
		setHorizontalScrollBarEnabled(false);
		setVerticalScrollBarEnabled(true);
		setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);
		
		this.contentList = new LinearLayout(context);
		this.contentList.setOrientation(LinearLayout.VERTICAL);
		this.addView(contentList);
		
		android.view.ViewGroup.LayoutParams lp = new android.view.ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
		
		this.headText = newText("");
		this.headText.setLayoutParams(lp);
		this.headText.setBackgroundColor(fontColor);
		this.headText.setTextColor(Color.BLACK);
		this.tailText = newText("");
		this.tailText.setLayoutParams(lp);
		this.tailText.setBackgroundColor(fontColor);
		this.tailText.setTextColor(Color.BLACK);
		
		this.lineHeight = this.headText.getMeasuredHeight();
		
		this.currFile = currFile;
		this.showImage = currFile.file.getName().endsWith(".lnd"); 
		this.fileParent = currFile.file.getParent() + "/";
	}
	
	
	public void reset(int seq) {
		seqFrom = seqTo = seq;
		contentList.removeAllViews();
		
		contentList.addView(headText);
		contentList.addView(tailText);
		
		headText.setText(loadingStr);
		tailText.setText(loadingStr);
		headText.setMinHeight(screenHeight);
		justReset = true;
	}
	
	public View createAppendar(int startOffset) {
		if (appendarList != null) return null;
		this.appendarList = new LinearLayout(getContext());
		this.appendarList.setOrientation(LinearLayout.VERTICAL);
		this.pendingHeight = 0;
		this.startOffset = startOffset;
		return appendarList;
	}
	
	public View addItem(String raw) {
		if (showImage && raw.startsWith("!")) {
			if (raw.startsWith("!!")) {
				return addText(raw.substring(1));
			} else {
				String relPath = raw.substring(1);
				if (relPath.startsWith("/")) {
					return addImage(fileParent + relPath.substring(1));
				} else {
					return addImage(fileParent + relPath);
				}
			}
		} else {
			return addText(raw);
		}
	}
	
	private View addText(String txt) {
		TextView txtView = newText(txt);
		pendingHeight += txtView.getMeasuredHeight();
		appendarList.addView(txtView);
		return txtView;
	}

	private TextView newText(String txt) {
		TextView txtView = new TextView(this.getContext());
		txtView.setTextSize(fontSize);
		txtView.setTextColor(fontColor);
		txtView.setText(txt);
		txtView.measure(MeasureSpec.makeMeasureSpec(screenWidth,
				MeasureSpec.AT_MOST), MeasureSpec.UNSPECIFIED);
		return txtView;
	}
	
	private View addImage(final String imgPath) {
		Bitmap bmp = null;
		if (imgPath.startsWith("+")) {
			try {
				int zfIndex = imgPath.indexOf('+', 1);
				ZipFile zipFile = new ZipFile(imgPath.substring(1, zfIndex));
				try {
					ZipEntry entry = zipFile.getEntry(imgPath.substring(zfIndex + 1));
					InputStream stream = zipFile.getInputStream(entry);
					try {
						bmp = BitmapFactory.decodeStream(stream);
					} finally {
						stream.close();
					}
				} finally {
					zipFile.close();
				}
			} catch (Throwable e) {
				Log.e("LNReader", "Error loading img from zip", e);
			}
		} else {
			File imgFile = new File(imgPath);
			if (!imgFile.isFile()) {
				return addText("文件不存在:" + imgPath);
			}
			BitmapFactory.Options o = new BitmapFactory.Options();
			o.inJustDecodeBounds = true;
			BitmapFactory.decodeFile(imgPath, o);
			int scale = 1;
			while(o.outWidth/scale/2>=screenWidth)
	            scale*=2;
			BitmapFactory.Options o2 = new BitmapFactory.Options();
	        o2.inSampleSize=scale;
	        bmp = BitmapFactory.decodeFile(imgPath, o2);
		}
		if (bmp == null) {
			return addText("无法载入:" + imgPath);
		}
		int width = screenWidth;
		if (bmp.getWidth() > width) {
			int scaledHeight = bmp.getHeight() * width / bmp.getWidth();
			bmp = Bitmap.createScaledBitmap(bmp, width, scaledHeight, true);
		}
		ImageView imgView = new ImageView(this.getContext());
		imgView.setImageBitmap(bmp);
		imgView.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(getContext(), ImageViewerActivity.class);
				intent.putExtra(ImageViewerActivity.DST_IMG, imgPath);
				getContext().startActivity(intent);
			}
		});
		pendingHeight += bmp.getHeight();
		appendarList.addView(imgView);
		return imgView;
	}
	
	private void updateHeadTailText() {
		if (seqFrom == 0) {
			headText.setText(headReachStr);
		} else {
			headText.setText(loadingStr);
		}
		
		if (seqTo < currFile.maxLineSeq) {
			tailText.setText(loadingStr);
		} else {
			tailText.setText(tailReachStr);
		}
	}
	
	public void cancelAppender() {
		appendarList = null;
	}
	
	public void flushAppenderAfter(final int endOffset) {
		if (justReset) {
			justReset = false;
			headText.setMinHeight(0);
			contentList.addView(appendarList, 1);
			scrollTo(0, lineHeight);
		} else {
			int scrollY = getScrollY();
			
			int lowestTop = scrollY - (screenHeight << 1) - 100;
			lowestTop = Math.min(lowestTop, contentList.getHeight() - viewHeightLimit);
			
			int removeHeight = 0;
			for (;;) {
				LinearLayout tmp = (LinearLayout) contentList.getChildAt(1);
				if (tmp == null) break;
				if (tmp.getBottom() >= lowestTop) {
					break; 
				}
				removeHeight += tmp.getHeight();
				seqFrom += tmp.getChildCount();
				contentList.removeViewAt(1);
			}
			contentList.addView(appendarList, contentList.getChildCount() - 1);
			scrollTo(0, scrollY - removeHeight);
		}
		seqTo += appendarList.getChildCount();
		updateHeadTailText();
		int[] offsetRange = new int[] {startOffset, endOffset};
		appendarList.setTag(offsetRange);
		appendarList = null;
	}
	
	public void flushAppenderBefore(final int endOffset) {
		if (justReset) throw new IllegalStateException();
		
		int scrollY = getScrollY();
		
		int removeIndex = contentList.getChildCount() - 2;
		int highestBottom = scrollY + (screenHeight << 2) + 100;
		highestBottom = Math.max(highestBottom, viewHeightLimit);
		
		for (;removeIndex > 0;) {
			LinearLayout tmp = (LinearLayout)contentList.getChildAt(removeIndex);
			if (tmp == null) break;
			if (tmp.getTop() < highestBottom) {
				break;
			}
			seqTo -= tmp.getChildCount();
			contentList.removeViewAt(removeIndex--);
		}
		
		tailText.setMinHeight(lineHeight + pendingHeight);
		
		post(new Runnable() {
			@Override
			public void run() {
				tailText.setMinHeight(0);
				contentList.addView(appendarList, 1);
				scrollTo(0, getScrollY() + pendingHeight);
				seqFrom -= appendarList.getChildCount();
				updateHeadTailText();
				int[] offsetRange = new int[] {startOffset, endOffset};
				appendarList.setTag(offsetRange);
				appendarList = null;
			}
		});
	}
	
	public int getPendingHeight() {
		return pendingHeight;
	}


	public int getSeqFrom() {
		return seqFrom;
	}


	public int getSeqTo() {
		return seqTo;
	}
	
	/**
	 * 获取当前的显示位置信息
	 * @return 	int[3],其中[0]表示显示范围内第一个控件的所在行号，
	 * 			[1]表示显示的便宜量.
	 * 			[2]表示百分比
	 */
	public int[] getPosition() {
		int oCount = contentList.getChildCount() - 1;
		int scrollY = getScrollY();
		int[] ret = new int[] {seqFrom, 0, 0};
		for (int i=1; i<oCount; i++) {
			LinearLayout txtBatch = (LinearLayout) contentList.getChildAt(i);
			if (txtBatch.getBottom() > scrollY) {
				int iCount = txtBatch.getChildCount();
				int lastBatchTop = txtBatch.getTop();
				int innerScrollY = scrollY - lastBatchTop;
				if (innerScrollY < 0) innerScrollY = 0;
				int[] offsetRange = (int[]) txtBatch.getTag();
				ret[2] = (offsetRange[0] * 100  + (offsetRange[1] - offsetRange[0]) * (100 * innerScrollY  / txtBatch.getHeight())) / currFile.fileSize;
				for (int j=0; j<iCount; j++) {
					View lastView = txtBatch.getChildAt(j);
					if (lastView.getBottom() > innerScrollY) {
						ret[1] = innerScrollY - lastView.getTop();
						return ret;
					}
					ret[0]++;
				}
				break;
			} else {
				ret[0] += txtBatch.getChildCount();
			}
		}
		ret[0] --;
		return ret;
	}

	public int getContentHeight() {
		return contentList.getHeight();
	}

	public int getScreenHeight() {
		return screenHeight;
	}
	
	public Object getFirstTextTag() {
		return contentList.getChildAt(1).getTag();
	}
	
	public void scrollNextPage() {
		smoothScrollBy(0, this.getHeight() - lineHeight);
	}

	public void scrollPrevPage() {
		smoothScrollBy(0, lineHeight - this.getHeight());
	}


	public void setShowImage(boolean showImage) {
		this.showImage = showImage;
	}


	public boolean isShowImage() {
		return showImage;
	}

}
